home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-19 / iritsm3s.zip / IRIT2RAY.C < prev    next >
C/C++ Source or Header  |  1992-02-26  |  24KB  |  791 lines

  1. /*****************************************************************************
  2. * Filter to convert IRIT data files to ray shade format.             *
  3. *                                         *
  4. * Written by:  Gershon Elber                Ver 1.0, Sep 1991    *
  5. *****************************************************************************/
  6.  
  7. #ifdef __MSDOS__
  8. #include <dos.h>
  9. #include <alloc.h>
  10. #endif /* __MSDOS__ */
  11.  
  12. #include <stdio.h>
  13. #include <math.h>
  14. #include <string.h>
  15. #include <time.h>
  16. #include "irit_sm.h"
  17. #include "iritprsr.h"
  18. #include "getarg.h"
  19. #include "genmat.h"
  20.  
  21. #define DIST_EPSILON    2e-4
  22. #define SIZE_EPSILON    1e-5
  23. #define CONVEX_EPSILON  1e-3
  24.  
  25. #ifdef __MSDOS__
  26. extern unsigned int _stklen = 32766;         /* Increase default stack size. */
  27. #endif /* __MSDOS__ */
  28.  
  29. #ifdef NO_CONCAT_STR
  30. static char *VersionStr =
  31.     "Irit2Ray        Version 3.0,    Gershon Elber,\n\
  32.      (C) Copyright 1989/90/91 Gershon Elber, Non commercial use only.";
  33. #else
  34. static char *VersionStr = "Irit2Ray    " VERSION ",    Gershon Elber,    "
  35.     __DATE__ ",   " __TIME__ "\n"
  36.     "(C) Copyright 1989/90/91 Gershon Elber, Non commercial use only.";
  37. #endif /* NO_CONCAT_STR */
  38.  
  39. static char
  40.     *CtrlStr = "irit2ray l%- 4%- G%-GridSize!d f%-FineNess!d o%-OutName!s g%- z%- DFiles!*s";
  41. static char
  42.     *OutFileName = "irit2ray";
  43.  
  44. static int
  45.     GlblGridSize = 5,
  46.     GlblGridFlag = FALSE,
  47.     GlblFineNess = 5,
  48.     GlblDumpOnlyGeometry = FALSE,
  49.     FourPerFlat = FALSE;
  50.  
  51. static MatrixType CrntViewMat;            /* This is the current view! */
  52.  
  53. static int TransColorTable[][4] = {
  54.     { /* BLACK        */ 0,    0,   0,   0 },
  55.     { /* BLUE        */ 1,    0,   0, 255 },
  56.     { /* GREEN        */ 2,    0, 255,   0 },
  57.     { /* CYAN        */ 3,    0, 255, 255 },
  58.     { /* RED        */ 4,  255,   0,   0 },
  59.     { /* MAGENTA     */ 5,  255,   0, 255 },
  60.     { /* BROWN        */ 6,   50,   0,   0 },
  61.     { /* LIGHTGRAY    */ 7,  127, 127, 127 },
  62.     { /* DARKGRAY    */ 8,   63,  63,  63 },
  63.     { /* LIGHTBLUE    */ 9,    0,   0, 255 },
  64.     { /* LIGHTGREEN    */ 10,   0, 255,   0 },
  65.     { /* LIGHTCYAN    */ 11,   0, 255, 255 },
  66.     { /* LIGHTRED    */ 12, 255,   0,   0 },
  67.     { /* LIGHTMAGENTA    */ 13, 255,   0, 255 },
  68.     { /* YELLOW        */ 14, 255, 255,   0 },
  69.     { /* WHITE        */ 15, 255, 255, 255 },
  70.     { /* BROWN        */ 20,  50,   0,   0 },
  71.     { /* DARKGRAY    */ 56,  63,  63,  63 },
  72.     { /* LIGHTBLUE    */ 57,   0,   0, 255 },
  73.     { /* LIGHTGREEN    */ 58,   0, 255,   0 },
  74.     { /* LIGHTCYAN    */ 59,   0, 255, 255 },
  75.     { /* LIGHTRED    */ 60, 255,   0,   0 },
  76.     { /* LIGHTMAGENTA    */ 61, 255,   0, 255 },
  77.     { /* YELLOW        */ 62, 255, 255,   0 },
  78.     { /* WHITE        */ 63, 255, 255, 255 },
  79.     {               -1,   0,   0,   0 }
  80. };
  81.  
  82. static IPObjectStruct *MainGetDataFiles(char **DataFileNames,
  83.                     int NumOfDataFiles);
  84. static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf, int FourPerFlat,
  85.                                 int FineNess);
  86. static void DumpDataForRayShade(IPObjectStruct *PObjects);
  87. static int DumpOneObject(FILE *FRay, FILE *FGeom, IPObjectStruct *PObject);
  88. static int DumpOnePolygon(FILE *f, IPPolygonStruct *PPolygon);
  89. static int IsConvexPolygon(IPPolygonStruct *Pl);
  90. static RealType *MapPoint(RealType *Pt);
  91. static RealType *MapVector(RealType *Pt, RealType *Vec);
  92. static void MyExit(int ExitCode);
  93.  
  94. /*****************************************************************************
  95. * Main routine - Read Parameter    line and do what you need...             *
  96. *****************************************************************************/
  97. void main(int argc, char **argv)
  98. {
  99.     int Error,
  100.     FineNessFlag = FALSE,
  101.     LinearOnePolyFlag = FALSE,
  102.     VerFlag = FALSE,
  103.     OutFileFlag = FALSE,
  104.     NumFiles = 0;
  105.     char Line[LINE_LEN_LONG], *p,
  106.     **FileNames = NULL;
  107.     IPObjectStruct *PObjects;
  108.  
  109. #ifdef __MSDOS__
  110.     ctrlbrk((int (*)()) MyExit);              /* Kill process if ^C. */
  111. #endif /* __MSDOS__ */
  112.  
  113.     if ((Error = GAGetArgs (argc, argv, CtrlStr, &LinearOnePolyFlag,
  114.                 &FourPerFlat, &GlblGridFlag, &GlblGridSize,
  115.                 &FineNessFlag, &GlblFineNess,  &OutFileFlag,
  116.                 &OutFileName, &GlblDumpOnlyGeometry,
  117.                 &VerFlag, &NumFiles, &FileNames)) != 0) {
  118.     GAPrintErrMsg(Error);
  119.     GAPrintHowTo(CtrlStr);
  120.     MyExit(1);
  121.     }
  122.  
  123.     if (VerFlag) {
  124.     fprintf(stderr, "\n%s\n\n", VersionStr);
  125.     GAPrintHowTo(CtrlStr);
  126.     MyExit(0);
  127.     }
  128.  
  129.     if (LinearOnePolyFlag) {
  130.     fprintf(stderr, "Linear patch side will have a single polygon.\n");
  131.     CagdSetLinear2Poly(CAGD_ONE_POLY_PER_COLIN);
  132.     }
  133.     else
  134.         CagdSetLinear2Poly(CAGD_REG_POLY_PER_LIN);
  135.  
  136.     fprintf(stderr, "%s triangles per flat will be created.\n",
  137.         FourPerFlat ? "Four" : "Two");
  138.  
  139.     if (!NumFiles) {
  140.     fprintf(stderr, "No data file names where given, exit.\n");
  141.     GAPrintHowTo(CtrlStr);
  142.     MyExit(1);
  143.     }
  144.  
  145.     if (!OutFileFlag) {        /* Pick the first input name as output name. */
  146.     strcpy(Line, FileNames[0]);
  147.     if ((p = strrchr(Line, '.')) != NULL);        /* Remove old file type. */
  148.         *p = 0;
  149.     OutFileName = malloc(strlen(Line) + 1);
  150.     strcpy(OutFileName, Line);
  151.     }
  152.  
  153.     /* Get the data files: */
  154.     IritPrsrPolyListCirc = FALSE;
  155.     PObjects = MainGetDataFiles(FileNames, NumFiles);
  156.  
  157.     if (IritPrsrWasPrspMat)
  158.     MultTwo4by4(CrntViewMat, IritPrsrViewMat, IritPrsrPrspMat);
  159.     else
  160.     GEN_COPY(CrntViewMat, IritPrsrViewMat, sizeof(MatrixType));
  161.  
  162.     DumpDataForRayShade(PObjects);
  163.  
  164.     MyExit(0);
  165. }
  166.  
  167. /*****************************************************************************
  168. * Main routine to read the data    description files:                 *
  169. * Returns pointer to pointers on FileDescription structures (one per file).  *
  170. *****************************************************************************/
  171. static IPObjectStruct *MainGetDataFiles(char **DataFileNames,
  172.                     int NumOfDataFiles)
  173. {
  174.     int    i;
  175.     FILE *f;
  176.     char
  177.     *ErrorMsg = NULL;
  178.     IPObjectStruct *PObj, *PObjTail,
  179.     *PObjHead = NULL;
  180.  
  181.     for    (i = 0; i < NumOfDataFiles; i++) {
  182. #ifdef __MSDOS__
  183.     if ((f = fopen(*DataFileNames, "rt")) == NULL) {   /* Open the file. */
  184. #else
  185.     if ((f = fopen(*DataFileNames, "r")) == NULL) {    /* Open the file. */
  186. #endif /* __MSDOS__ */
  187.         fprintf(stderr, "Can't open data file %s\n", *DataFileNames);
  188.         MyExit(1);
  189.     }
  190.  
  191.     if ((PObj = IritPrsrGetObjects(f)) != NULL) {  /* Get the data file. */
  192.         PObjTail = PObj;
  193.         while (PObjTail -> Pnext) PObjTail = PObjTail -> Pnext;
  194.         PObjTail -> Pnext = PObjHead;
  195.         PObjHead = PObj;
  196.     }
  197.  
  198.     fclose(f);                      /* Close the file. */
  199.  
  200.     if (IritPrsrParseError(&ErrorMsg)) {
  201.         fprintf(stderr, "Parse error in \"%s\":\n%s\n", *DataFileNames, ErrorMsg);
  202.         MyExit(1);
  203.     }
  204.  
  205.     DataFileNames++;              /* Skip to next file name. */
  206.     }
  207.  
  208.     if (PObjHead == NULL) {
  209.     fprintf(stderr, "No data found.\n");
  210.     MyExit(1);
  211.     }
  212.  
  213.     return PObjHead;
  214. }
  215.  
  216. /*****************************************************************************
  217. * Routine to convert all surfaces/curves into polylines as follows:         *
  218. * Curves are converted to single polyline with SamplesPerCurve samples.         *
  219. * Surface are converted into GlblNumOfIsolines curves in each axes, each     *
  220. * handled as Curves above. The curves and surfaces are then deleted.         *
  221. *****************************************************************************/
  222. IPObjectStruct *IritPrsrProcessFreeForm(IPObjectStruct *CrvObjs,
  223.                     IPObjectStruct *SrfObjs)
  224. {
  225.     int LocalFourPerFlat;
  226.     float RelativeFineNess;
  227.     CagdCrvStruct *Crvs;
  228.     CagdSrfStruct *Srf, *Srfs;
  229.     IPObjectStruct *PObj, *PObjNext;
  230.     IPPolygonStruct *PPolygon, *PPolygonTemp;
  231.  
  232.     if (CrvObjs == NULL && SrfObjs == NULL) return NULL;
  233.  
  234.     /* Make sure requested format is something reasonable. */
  235.     if (GlblFineNess < 2) {
  236.     GlblFineNess = 2;
  237.     fprintf(stderr, "FineNess is less than 2, 2 picked instead.\n");
  238.     }
  239.  
  240.     if (CrvObjs) {
  241.     /* Curves are not rendered at this time and they are ignored. */
  242.     for (PObj = CrvObjs; PObj != NULL;) {
  243.         Crvs = PObj -> U.PCrvs;
  244.         CagdCrvFreeList(Crvs);
  245.         PObjNext = PObj -> Pnext;
  246.         free((VoidPtr) PObj);
  247.         PObj = PObjNext;
  248.     }
  249.     CrvObjs = NULL;
  250.     }
  251.  
  252.     if (SrfObjs) {
  253.     for (PObj = SrfObjs; PObj != NULL; PObj = PObj -> Pnext) {
  254.         CagdBBoxStruct BBox, TempBBox;
  255.         char GridStr[LINE_LEN], *p;
  256.  
  257.         Srfs = PObj -> U.PSrfs;
  258.         PObj -> U.PPolygon = NULL;
  259.  
  260.         RelativeFineNess = 1.0;
  261.         LocalFourPerFlat = FourPerFlat;
  262.  
  263.         if (IritPrsrGetStrAttrib(PObj, "twoperflat"))
  264.         LocalFourPerFlat = FALSE;
  265.         if (IritPrsrGetStrAttrib(PObj, "fourperflat"))
  266.         LocalFourPerFlat = TRUE;
  267.  
  268.         if ((p = IritPrsrGetStrAttrib(PObj, "resolution")) != NULL &&
  269.         sscanf(p, "%f", &RelativeFineNess) != 1)
  270.         RelativeFineNess = 1.0;
  271.  
  272.         for (Srf = Srfs; Srf != NULL; Srf = Srf -> Pnext) {
  273.         if (GlblGridFlag) {
  274.             /* Generate bounding box to the surfaces and estimate */
  275.             /* the grid size for it using GlblGridSize.          */
  276.             if (Srf == Srfs)
  277.             CagdSrfBBox(Srf, &BBox);
  278.             else {
  279.             CagdSrfBBox(Srf, &TempBBox);
  280.             CagdMergeBBox(&BBox, &TempBBox);
  281.             }
  282.         }
  283.         PPolygon = PPolygonTemp =
  284.             Surface2Polygons(Srf, LocalFourPerFlat,
  285.                      (int) (RelativeFineNess * GlblFineNess));
  286.         while (PPolygonTemp -> Pnext)
  287.             PPolygonTemp = PPolygonTemp -> Pnext;
  288.         PPolygonTemp -> Pnext = PObj -> U.PPolygon;
  289.         PObj -> U.PPolygon = PPolygon;
  290.         }
  291.         CagdSrfFreeList(Srfs);
  292.  
  293.         if (GlblGridFlag) {
  294.         RealType
  295.             Dx = BBox.Max[0] - BBox.Min[0],
  296.             Dy = BBox.Max[1] - BBox.Min[1],
  297.             Dz = BBox.Max[2] - BBox.Min[2],
  298.             M = MAX(MAX(Dx, Dy), Dz);
  299.         int IDx = (int) (GlblGridSize * (Dx / M)),
  300.             IDy = (int) (GlblGridSize * (Dy / M)),
  301.             IDz = (int) (GlblGridSize * (Dz / M));
  302.  
  303.         /* Save grid information derived from the surface bbox. */
  304.         sprintf(GridStr, "%d %d %d",
  305.             IDx > 0 ? IDx : 1,
  306.             IDy > 0 ? IDy : 1,
  307.             IDz > 0 ? IDz : 1);
  308.         IritPrsrSetStrAttrib(PObj, "GridSize", GridStr);
  309.         }
  310.     }
  311.     }
  312.  
  313.     return SrfObjs;
  314. }
  315.  
  316. /*****************************************************************************
  317. * Routine to convert a single surface into a polylines with SamplesPerCurve  *
  318. * samples, NumOfIsolines isolines into a polyline object list.             *
  319. *****************************************************************************/
  320. static IPPolygonStruct *Surface2Polygons(CagdSrfStruct *Srf, int FourPerFlat,
  321.                      int FineNess)
  322. {
  323.     int i, j;
  324.     IPVertexStruct *V, *VHead,
  325.     *VTail = NULL;
  326.     IPPolygonStruct *P,
  327.     *PHead = NULL;
  328.     CagdPolygonStruct *CagdPolygon,
  329.     *CagdPolygonHead = CagdSrf2Polygons(Srf, FineNess, TRUE, FourPerFlat);
  330.  
  331.     for (CagdPolygon = CagdPolygonHead, VHead = NULL;
  332.      CagdPolygon != NULL;
  333.      CagdPolygon = CagdPolygon -> Pnext) {
  334.     /* All polygons are triangles! */
  335.  
  336.     for (i = 0, VHead = NULL; i < 3; i++) {         /* Convert to vertices. */
  337.         V = IritPrsrNewVertexStruct();
  338.         IP_SET_VRTX_NORMAL(V);             /* This vertex has normal. */
  339.  
  340.         for (j = 0; j < 3; j++)                /* Convert to our format. */
  341.            V -> Coord[j] = CagdPolygon -> Polygon[i].Pt[j];
  342.         for (j = 0; j < 3; j++)
  343.            V -> Normal[j] = CagdPolygon -> Normal[i].Vec[j];
  344.  
  345.         if (VHead) {
  346.         VTail -> Pnext = V;
  347.         VTail = V;
  348.         }
  349.         else
  350.         VHead = VTail = V;
  351.     }
  352.  
  353.     P = IritPrsrNewPolygonStruct();
  354.     P -> PVertex = VHead;
  355.     P -> Type = IP_POLYGON;
  356.     P -> Pnext = PHead;
  357.  
  358.     PHead = P;
  359.     }
  360.  
  361.     CagdPolygonFreeList(CagdPolygonHead);
  362.  
  363.     return PHead;
  364. }
  365.  
  366. /*****************************************************************************
  367. * Dumps the data for ray shade into stdout.                     *
  368. *****************************************************************************/
  369. static void DumpDataForRayShade(IPObjectStruct *PObjects)
  370. {
  371.     static char *Header1[] = {
  372.     "/*",
  373.     " * This file was automatically created from IRIT solid modeller data",
  374.     " * using Irit2ray - IRIT to RayShade filter.",
  375.     " *",
  376.     " *            (c) Copyright 1991/92 Gershon Elber, Non commercial use only.",
  377.     " */",
  378.     "",
  379.     NULL
  380.     };
  381.     static char *Header2[] = {
  382.     "",
  383.     "eyep   0  0 10",
  384.     "lookp  0  0  0",
  385.     "up     0  1  0",
  386.     "fov 12",
  387.     "",
  388.     "light 1 1 1 point 10 30 10",
  389.     "",
  390.     NULL
  391.     };
  392.     int i,
  393.     TotalPolys = 0;
  394.     char Line[128];
  395.     IPObjectStruct *PObj,
  396.     *PObjHead = NULL;
  397.     FILE *FGeom, *FRay;
  398.  
  399.     sprintf(Line, "%s.ray", OutFileName);
  400.     if (!GlblDumpOnlyGeometry) {
  401.     if ((FRay = fopen(Line, "w")) == NULL) {
  402.         fprintf(stderr, "Failed to open \"%s\".\n", Line);
  403.         exit(2);
  404.     }
  405.     }
  406.     else
  407.     FRay = NULL;
  408.  
  409.     sprintf(Line, "%s.geom", OutFileName);
  410.     if ((FGeom = fopen(Line, "w")) == NULL) {
  411.     fprintf(stderr, "Failed to open \"%s\".\n", Line);
  412.     exit(2);
  413.     }
  414.  
  415.     if (FRay != NULL)
  416.     for (i = 0; Header1[i] != NULL; i++)
  417.         fprintf(FRay, "%s\n", Header1[i]);
  418.     for (i = 0; Header1[i] != NULL; i++)
  419.     fprintf(FGeom, "%s\n", Header1[i]);
  420.  
  421.     /* Reverse object list since it was loaded in reverse by iritprsr module.*/
  422.     while (PObjects != NULL) {
  423.     PObj = PObjects;
  424.     PObjects = PObjects -> Pnext;
  425.     PObj -> Pnext = PObjHead;
  426.     PObjHead = PObj;
  427.     }
  428.     PObjects = PObjHead;
  429.  
  430.     while (PObjects) {
  431.     TotalPolys += DumpOneObject(FRay, FGeom, PObjects);
  432.     PObjects = PObjects -> Pnext;
  433.     }
  434.  
  435.     if (FRay != NULL) {
  436.     fprintf(FRay, "#include \"%s\"\n", Line);
  437.     for (i = 0; Header2[i] != NULL; i++)
  438.         fprintf(FRay, "%s\n", Header2[i]);
  439.     fclose(FRay);
  440.     }
  441.  
  442.     fclose(FGeom);
  443.  
  444.     fprintf(stderr, "\nTotal number of polygons - %d\n", TotalPolys);
  445. }
  446.  
  447. /*****************************************************************************
  448. * Routine to dump one object PObject.                         *
  449. *****************************************************************************/
  450. static int DumpOneObject(FILE *FRay, FILE *FGeom, IPObjectStruct *PObject)
  451. {
  452.     static int
  453.     ObjectSeqNum = 1;
  454.     int i, j,
  455.         PolyCount = 0,
  456.     HasColor = FALSE,
  457.     HasSrfProp = FALSE;
  458.     char *p, Name[LINE_LEN], SrfPropString[LINE_LEN_LONG];
  459.     RealType RGBColor[3];
  460.     IPPolygonStruct
  461.     *PList = PObject -> U.PPolygon;
  462.  
  463.     if (strlen(PObject -> Name) == 0)
  464.     sprintf(Name, "ObjSeq%d", ObjectSeqNum);
  465.     else
  466.     strcpy(Name, PObject -> Name);
  467.  
  468.     SrfPropString[0] = 0;
  469.     for (i = 0; i < PObject -> Attrs.NumStrAttribs; i++)
  470.     {
  471.     if (strcmp(PObject -> Attrs.StrAttrName[i], "specpow") == 0 ||
  472.         strcmp(PObject -> Attrs.StrAttrName[i], "reflect") == 0 ||
  473.         strcmp(PObject -> Attrs.StrAttrName[i], "transp") == 0 ||
  474.         strcmp(PObject -> Attrs.StrAttrName[i], "body") == 0 ||
  475.         strcmp(PObject -> Attrs.StrAttrName[i], "index") == 0) {
  476.         strcat(SrfPropString, PObject -> Attrs.StrAttrName[i]);
  477.         strcat(SrfPropString, " ");
  478.         strcat(SrfPropString, PObject -> Attrs.StrAttrData[i]);
  479.         strcat(SrfPropString, " ");
  480.         HasSrfProp = TRUE;
  481.     }
  482.     }
  483.  
  484.     if (GlblGridFlag) {
  485.     char *GridStr = IritPrsrGetStrAttrib(PObject, "GridSize");
  486.  
  487.     if (GridStr != NULL)
  488.         fprintf(FGeom, "name %s grid %s\n", Name, GridStr);
  489.     else
  490.         fprintf(FGeom, "name %s list\n", Name);
  491.     }
  492.     else
  493.     fprintf(FGeom, "name %s list\n", Name);
  494.  
  495.     while (PList) {
  496.     PolyCount += DumpOnePolygon(FGeom, PList);
  497.     PList =    PList -> Pnext;
  498.     }
  499.     fprintf(FGeom, "end\n");
  500.  
  501.     fprintf(stderr, "Processing \"%s\" - %d triangles.\n", Name, PolyCount);
  502.  
  503.     if ((p = IritPrsrGetStrAttrib(PObject, "rgb")) != NULL)
  504.     {
  505. #    ifdef __MSDOS__
  506.         HasColor = sscanf(p, "%f,%f,%f",
  507. #    else
  508.         HasColor = sscanf(p, "%lf,%lf,%lf",
  509. #    endif /* __MSDOS__ */
  510.                   &RGBColor[0], &RGBColor[1], &RGBColor[2]) == 3;    
  511.     }
  512.     else if (IP_HAS_OBJ_RGB(PObject)) {
  513.     HasColor = TRUE;
  514.     for (i = 0; i < 3; i++) RGBColor[i] = PObject -> RGB[i];
  515.     }
  516.     else if (IP_HAS_OBJ_COLOR(PObject)) {
  517.     for (i = 0; TransColorTable[i][0] >= 0; i++) {
  518.         if (TransColorTable[i][0] == PObject -> Color) {
  519.         HasColor = TRUE;
  520.         for (j = 0; j < 3; j++) RGBColor[j] = TransColorTable[i][j+1];
  521.         break;
  522.         }
  523.     }
  524.     }
  525.  
  526.     if (HasColor || HasSrfProp) {
  527.     if (FRay != NULL) {
  528.         fprintf(FRay, "surface %sSrfProp\n", Name);
  529.         if (HasColor) {
  530.         for (i = 0; i < 3; i++) RGBColor[i] /= 255.0;
  531.  
  532.         fprintf(FRay, "\tambient  %7.4lf %7.4lf %7.4lf\n",
  533.             0.1 * RGBColor[0],
  534.             0.1 * RGBColor[1],
  535.             0.1 * RGBColor[2]);
  536.         fprintf(FRay, "\tdiffuse  %7.4lf %7.4lf %7.4lf\n",
  537.             0.7 * RGBColor[0],
  538.             0.7 * RGBColor[1],
  539.             0.7 * RGBColor[2]);
  540.         fprintf(FRay, "\tspecular %7.4lf %7.4lf %7.4lf\n",
  541.             0.8, 0.8, 0.8);
  542.         }
  543.         if (HasSrfProp)
  544.         fprintf(FRay, "\t%s\n", SrfPropString);
  545.     }
  546.  
  547.     fprintf(FGeom, "object %sSrfProp %s", Name, Name);
  548.     }
  549.     else
  550.     fprintf(FGeom, "object %s", Name);
  551.  
  552.     for (i = 0; i < PObject -> Attrs.NumStrAttribs; i++) {
  553.     if ((p = IritPrsrGetStrAttrib(PObject, "texture")) != NULL) {
  554.         if (FRay != NULL)
  555.         fprintf(FRay, "#define %sTEXTURE %s\n", Name, p);
  556.         fprintf(FGeom, " texture %sTEXTURE", Name);
  557.         break;
  558.     }
  559.     }
  560.     fprintf(FGeom, "\n\n");
  561.     if (FRay != NULL)
  562.     fprintf(FRay, "\n\n");
  563.  
  564.     ObjectSeqNum++;
  565.  
  566.     return PolyCount;
  567. }
  568.  
  569. /*****************************************************************************
  570. * Routine to dump one polygon, using global Matrix transform CrntViewMat.    *
  571. *****************************************************************************/
  572. static int DumpOnePolygon(FILE *FGeom, IPPolygonStruct *PPolygon)
  573. {
  574.     int i,
  575.     TriCount = 0;
  576.     RealType *MappedNormal[3], *MappedPoint[3], Normal[3], Vec1[3], Vec2[3];
  577.     IPVertexStruct *VFirst, *V1, *V2,
  578.     *VList = PPolygon -> PVertex;
  579.  
  580.     if (VList == NULL) return 0;
  581.  
  582.     if (!IsConvexPolygon(PPolygon)) {
  583.     static int Printed = FALSE;
  584.  
  585.     if (!Printed) {
  586.         fprintf(stderr,
  587.             "Non convex polygon(s) may be in data (see CONVEX in IRIT).\n");
  588.         Printed = TRUE;
  589.     }
  590.     }
  591.  
  592.     switch (PPolygon -> Type) {
  593.     case IP_POLYGON:
  594.         VFirst = VList;
  595.         V1 = VFirst -> Pnext;
  596.         V2 = V1 -> Pnext;
  597.  
  598.         while (V2 != NULL) {
  599.         MappedPoint[0] = MapPoint(VFirst -> Coord);
  600.         MappedPoint[1] = MapPoint(V1 -> Coord);
  601.         MappedPoint[2] = MapPoint(V2 -> Coord);
  602.  
  603.         /* Test for two type of degeneracies. Make sure that no two  */
  604.         /* points in the triangle are the same and that they are     */
  605.         /* not colinear.                         */
  606.         if (!PT_EQ(MappedPoint[0], MappedPoint[1]) &&
  607.             !PT_EQ(MappedPoint[0], MappedPoint[2]) &&
  608.             !PT_EQ(MappedPoint[1], MappedPoint[2])) {
  609.  
  610.             PT_SUB(Vec1, MappedPoint[0], MappedPoint[1]);
  611.             PT_SUB(Vec2, MappedPoint[1], MappedPoint[2]);
  612.             PT_NORMALIZE(Vec1);
  613.             PT_NORMALIZE(Vec2);
  614.             CROSS_PROD(Normal, Vec1, Vec2);
  615.  
  616.             if (PT_LENGTH(Normal) > SIZE_EPSILON) {
  617.             PT_NORMALIZE(Normal);
  618.  
  619.             MappedNormal[0] =
  620.                 MapVector(VFirst -> Coord, VFirst -> Normal);
  621.             MappedNormal[1] =
  622.                 MapVector(V1 -> Coord, V1 -> Normal);
  623.             MappedNormal[2] =
  624.                 MapVector(V2 -> Coord, V2 -> Normal);
  625.  
  626.             if (DOT_PROD(Normal, MappedNormal[0]) < -SIZE_EPSILON ||
  627.                 DOT_PROD(Normal, MappedNormal[1]) < -SIZE_EPSILON ||
  628.                 DOT_PROD(Normal, MappedNormal[2]) < -SIZE_EPSILON) {
  629.                 SWAP(RealType *, MappedPoint[1], MappedPoint[2]);
  630.                 SWAP(RealType *, MappedNormal[1], MappedNormal[2]);
  631.                 PT_SCALE(Normal, -1.0);
  632.                 }
  633.  
  634.                 /* Make sure all normals are set properly: */
  635.                 if (DOT_PROD(MappedNormal[0], MappedNormal[0]) < SIZE_EPSILON)
  636.                 PT_COPY(MappedNormal[0], Normal);
  637.                 if (DOT_PROD(MappedNormal[1], MappedNormal[1]) < SIZE_EPSILON)
  638.                 PT_COPY(MappedNormal[1], Normal);
  639.                 if (DOT_PROD(MappedNormal[2], MappedNormal[2]) < SIZE_EPSILON)
  640.                 PT_COPY(MappedNormal[2], Normal);
  641.  
  642.                 TriCount++;
  643.  
  644.                 for (i = 0; i < 3; i++)
  645.                     fprintf(FGeom,
  646.                 "%s %10.7lf %10.7lf %10.7lf  %9.6lf %9.6lf %9.6lf\n",
  647.                 i == 0 ? "    triangle" : "\t    ",
  648.                 MappedPoint[i][0],
  649.                 MappedPoint[i][1],
  650.                 MappedPoint[i][2],
  651.                 MappedNormal[i][0],
  652.                 MappedNormal[i][1],
  653.                 MappedNormal[i][2]);
  654.             }
  655.         }
  656.  
  657.         V1 = V2;
  658.         V2 = V2 -> Pnext;
  659.         }
  660.         break;
  661.     }
  662.  
  663.     return TriCount;
  664. }
  665.  
  666. /*****************************************************************************
  667. *   Routine to test if the given polygon is convex or not.             *
  668. * Algorithm: The polygon is convex iff the normals generated from cross      *
  669. * products of two consecutive edges points to the same direction. The same   *
  670. * direction is tested by a positive dot product.                 *
  671. *****************************************************************************/
  672. static int IsConvexPolygon(IPPolygonStruct *Pl)
  673. {
  674.     RealType Size, V1[3], V2[3], LastNormal[3], Normal[3];
  675.     IPVertexStruct *VNext, *VNextNext,
  676.     *V = Pl -> PVertex;
  677.  
  678.     LastNormal[0] = LastNormal[1] = LastNormal[2] = 0.0;
  679.  
  680.     do {
  681.     if ((VNext = V -> Pnext) == NULL)
  682.         VNext = Pl -> PVertex;
  683.     if ((VNextNext = VNext -> Pnext) == NULL)
  684.         VNextNext = Pl -> PVertex;
  685.  
  686.     PT_SUB(V1, VNext -> Coord, V -> Coord);
  687.     if ((Size = PT_LENGTH(V1)) > EPSILON) {
  688.         Size = 1.0 / Size;
  689.         PT_SCALE(V1, Size);
  690.     }
  691.     PT_SUB(V2, VNextNext -> Coord, VNext -> Coord);
  692.     if ((Size = PT_LENGTH(V2)) > EPSILON) {
  693.         Size = 1.0 / Size;
  694.         PT_SCALE(V2, Size);
  695.     }
  696.     CROSS_PROD(Normal, V1, V2);
  697.  
  698.     if (V != Pl -> PVertex) {
  699.         if (PT_LENGTH(Normal) > CONVEX_EPSILON &&
  700.         DOT_PROD(Normal, LastNormal) < -CONVEX_EPSILON)
  701.         return FALSE;
  702.     }
  703.  
  704.     PT_COPY(LastNormal, Normal);
  705.  
  706.     V = VNext;
  707.     }
  708.     while (V != Pl -> PVertex && V != NULL);
  709.  
  710.     return TRUE;
  711. }
  712.  
  713. /*****************************************************************************
  714. * Maps the given E3 point using the CrntViewMat.                 *
  715. *****************************************************************************/
  716. static RealType *MapPoint(RealType *Pt)
  717. {
  718.     static int Count = 0;
  719.     static RealType MappedPts[3][3];
  720.     RealType *MappedPt = MappedPts[Count++];
  721.  
  722.     if (Count >= 3) Count = 0;
  723.  
  724.     MultVecby4by4(MappedPt, Pt, CrntViewMat);
  725.  
  726.     return MappedPt;
  727. }
  728.  
  729. /*****************************************************************************
  730. * Maps the given E3 vector using the CrntViewMat.                 *
  731. * This routine will return a zero vector if normal is not computable.         *
  732. *****************************************************************************/
  733. static RealType *MapVector(RealType *Pt, RealType *Vec)
  734. {
  735.     static int
  736.     Count = 0,
  737.     WasWarning = 0;
  738.     static RealType MappedVecs[3][3];
  739.     RealType MappedPt[3], Pt2[3], MappedPt2[3],
  740.     *MappedVec = MappedVecs[Count++];
  741.  
  742.     if (Count >= 3) Count = 0;
  743.  
  744.     if (DOT_PROD(Vec, Vec) < SIZE_EPSILON) {
  745.     MappedVec[0] = MappedVec[1] = MappedVec[2] = 0.0;
  746.     if (!WasWarning) {
  747.         WasWarning = 1;
  748.         fprintf(stderr, "Non computable normals detected. Approximated from geometry.\n");
  749.     }
  750.     }
  751.     else {
  752.         MultVecby4by4(MappedPt, Pt, CrntViewMat);
  753.  
  754.         PT_ADD(Pt2, Pt, Vec);
  755.         MultVecby4by4(MappedPt2, Pt2, CrntViewMat);
  756.  
  757.         PT_SUB(MappedVec, MappedPt2, MappedPt);
  758.         PT_NORMALIZE(MappedVec);
  759.     }
  760.  
  761.     return MappedVec;
  762. }
  763.  
  764. /*****************************************************************************
  765. * Trap Cagd_lib errors right here.                         *
  766. *****************************************************************************/
  767. void CagdFatalError(CagdFatalErrorType ErrID)
  768. {
  769.     char
  770.     *ErrorMsg = CagdDescribeError(ErrID);
  771.  
  772.     fprintf(stderr, "CAGD_LIB: %s", ErrorMsg);
  773.  
  774.     exit(-1);
  775. }
  776.  
  777. /*****************************************************************************
  778. * MyExit routine. Note it might call to CloseGraph without calling         *
  779. * InitGraph(), or call MouseClose() without MouseInit() etc. and it is the   *
  780. * responsibility of the individual modules to do nothing in these cases.     *
  781. *****************************************************************************/
  782. static void MyExit(int ExitCode)
  783. {
  784. #ifdef __MSDOS__
  785.     fprintf(stderr,
  786.         "\nIrit2Ray: Core left %ldk.\n", coreleft() / 1024);
  787. #endif /* __MSDOS__ */
  788.  
  789.     exit(ExitCode);
  790. }
  791.